//------------------------------------------------------------------------------
// The confidential and proprietary information contained in this file may
// only be used by a person authorised under and to the extent permitted
// by a subsisting licensing agreement from ARM Limited.
//
//            (C) COPYRIGHT 2008-2012 ARM Limited.
//                ALL RIGHTS RESERVED
//
// This entire notice must be reproduced on all copies of this file
// and copies of this file may only be made by a person if such person is
// permitted to do so under the terms of a subsisting license agreement
// from ARM Limited.
//------------------------------------------------------------------------------
// Version and Release Control Information:
//
// File Revision       : 132589
// File Date           :  2012-06-27 11:21:28 +0100 (Wed, 27 Jun 2012)
// Release Information : PL401-r0p1-00eac0
//------------------------------------------------------------------------------
// Purpose             : A slot of the storage for the ID and hazard
//                       information required by the Downsizer R channel
//------------------------------------------------------------------------------

module nic400_ib_dma_axi4_cpu_ib_downsize_rd_cam_slice_ysyx_rv32
  (
    // global interconnect signals
    aresetn,
    aclk,

    // ID inputs (to all slices)
    match_id,        //ID arriving on the R Channel

    //Control Signals
    store,
    push_slice,
    pop_slice,
    update,
    match_pointer,

    //If a hazard has been detected
    hazard_in,
    hazard_pointer,

    //Inputs 
    
    //Data from ARformat Block
    archannel_data,
    
    //Data from downsizer read channel block
    ar_cam_data,            

    rdata_m,
    rresp_m,
    rlast_m,

    //Outputs
    hazard,
    match,
    last_addr_match,
    valid,
    beat_complete,
    beat_number,
    
    rdata_cam,
    
    rresp_cam,
    
    mask_last

  );

`include "nic400_ib_dma_axi4_cpu_ib_defs_ysyx_rv32.v"
`include "Axi.v"

  //------------------------------------------------------------------------------
  // IO 
  //------------------------------------------------------------------------------

  //System Inputs
  input                  aresetn;
  input                  aclk;

  input [3:0]            match_id;

  //Register update control signal
  input                  store;
  input                  push_slice;
  input                  pop_slice;
  input                  update;

  //Pointers to other Slices
  input                  hazard_pointer;
  input                  match_pointer;
  input                  hazard_in;

  //Data in from Format Block
  input [11:0]           archannel_data;
  input [10:0]           ar_cam_data;            

  input [31:0]           rdata_m;
  input [1:0]            rresp_m;
  input                  rlast_m;
  //The updated address

  output                 hazard;
  output                 valid;
  output                 match;
  output                 last_addr_match;
  output                 beat_complete;
  output [1:0]           beat_number;
  
  output [31:0]          rdata_cam;
  
  output [1:0]           rresp_cam;
  
  output                 mask_last;

 
 //------------------------------------------------------------------------
 // Registers
 //------------------------------------------------------------------------ 

  reg [3:0]             id_reg;
  reg                   pointer_reg;
  reg                   hazard_reg;
  reg                   valid_reg;
  reg                   last_reg;
  reg [3:0]               n_response_reg;
  reg [2:0]             addr_next;
  reg [2:0]             addr_reg;
  reg [2:0]             addr_mask_reg;
  reg [1:0]             addr_mask_end_reg;
  reg [1:0]             size_reg;
  reg                   bypass_reg;
  reg [2:0]             downsize_reg;
  
  reg [3:0]             size_incr;
  
  reg [1:0]             beats_masked;
  reg [1:0]             addr_end_masked;
  
  reg                   fixed_mask_reg;
  
  
  reg [31:0]            rdata_reg;  
  
  reg [1:0]             rresp_reg;
  
  

 //------------------------------------------------------------------------ 
 // Wires
 //------------------------------------------------------------------------

  wire [3:0]            next_id_reg;
  wire                  next_pointer_reg;

  //Register next values
  wire                  next_hazard_reg;
  wire                  next_valid_reg;
  wire                  next_last_reg;
  wire [3:0]               next_n_response_reg;
  wire [2:0]            next_addr_reg;
  wire [2:0]            next_addr_mask_reg;

  //match Signals
  wire                  allowed_to_match;
  wire                  rid_match;
  wire                  arid_match;
  wire                  pointer_match;

  //Register write enables
  wire                  last_reg_wr_en;
  wire                  hazard_reg_wr_en;
  wire                  valid_reg_wr_en;
  wire                  n_response_reg_wr_en;
  wire                  default_reg_wr_en;
  wire                  addr_reg_wr;
  wire                  fixed_incr_addr;

  //Signals from AR Format Block
  wire [1:0]            size_in;
  wire                  bypass_in;
  wire [2:0]            addr;
  wire [2:0]            addr_mask;
  wire [2:0]            addr_out;
  wire [3:0]               n_response;
  wire [1:0]            addr_mask_end;
  wire [3:0]            hazard_id;
  
  wire [2:0]            downsize;
  wire                  fixed_mask;
  
  wire [1:0]            beat_number;

  wire                  boundary_cross;
  wire [3:0]            addr_incr;
  wire                  can_complete;
  
  wire                  rdata_cam_valid;
  
  wire                  rresp_reg_en;
  
  wire [1:0]            rresp_reg_nxt;
  wire [1:0]            rresp_cam_nxt;
  
  wire                  data_select;
  
  wire                  rdata_reg_en;

  // Internal representations of outputs
  wire                  last_addr_match_i;
  wire                  match_i;
 //------------------------------------------------------------------------
 // Decode ARChannel_Data
 //------------------------------------------------------------------------

 assign addr_mask     = archannel_data[2:0];
 assign addr_mask_end = archannel_data[4:3];
 assign n_response    = fixed_mask ? {4{1'b0}} : archannel_data[8:5];
 assign downsize      = archannel_data[11:9];

 assign bypass_in     = ar_cam_data[0];
 assign fixed_mask    = ar_cam_data[1];
 assign size_in       = ar_cam_data[3:2];
 assign addr          = ar_cam_data[6:4];
 assign hazard_id     = ar_cam_data[10:7];

    
 
 //------------------------------------------------------------------------
 // Main Code
 //------------------------------------------------------------------------

 //id match Logic
 assign rid_match = (match_id == id_reg);
 assign arid_match = (hazard_id == id_reg);
 
 //match Output - This slice can only report a match if the rid matches, the
 //slice is valid, doesn't report a hazard 
 assign allowed_to_match = valid_reg && ~hazard_reg;
 assign match_i          = allowed_to_match && rid_match;
 assign match            = match_i;
 assign can_complete     = match_i && ~|n_response_reg;
 
 
 //------------------------------------------------------------------------
 // R Data path storage
 //------------------------------------------------------------------------

 
  
  //For 2:1 downsizing, data select is simply single bit of addr to determine
  //position on bus
  assign data_select = ~addr_out[2];
 //The narrow bus width data must be assembled into a full wide data width slot before being popped
 //from the cam slice. The following R data storage locations capture narrow sized data blocks.
 
 assign rdata_reg_en = (data_select) && downsize_reg[2] && match_i;
 
 always @(posedge aclk)
   begin : r_data_seq
     if (rdata_reg_en) begin
        rdata_reg <= rdata_m;
     end    
   end // r_data_seq
   
  
 //R data output is masked with 'match' to only be presented 
 //to the wide bus upon a match occuring.
 
 assign rdata_cam[31:0] = (rdata_cam_valid ? rdata_reg : rdata_m) & {32{match_i}}; 
 
 
 assign rresp_reg_en = (update && match_i);
 
 always @(posedge aclk or negedge aresetn)
  begin : rresp_reg_seq
    if (!aresetn)
       rresp_reg <= 2'b01;
    else if (rresp_reg_en)
       rresp_reg <= rresp_reg_nxt;    
  end // rresp_reg_seq
 
  // Reset the next rresp_reg to exokay if a beat is completing otherwise store
  // next output value;
  // exokay is the lowest priority value ... anything else is an error to it (inc okay)
  assign rresp_reg_nxt = boundary_cross ? 2'b01 : rresp_cam_nxt;

  // Generate required response. 
  // If stored response is exokay output incoming resp.
  // Else output the logical OR of the stored and incoming responses 
  // UNLESS incoming is exokay in which case don't change stored value;
  // This creates the priority scheme exokay, okay, slverr, decerr
  assign rresp_cam_nxt = (rresp_reg == 2'b01) ? rresp_m :
                         ((rresp_m != 2'b01) ? (rresp_reg | rresp_m) :
                         rresp_reg);
   
 always @(posedge aclk or negedge aresetn)
  begin : fixed_mask_seq
    if (!aresetn)
       fixed_mask_reg <= 1'b0;
    else if (default_reg_wr_en)
       fixed_mask_reg <= fixed_mask;    
  end // fixed_mask_seq
  
  
  
  assign rdata_cam_valid = downsize_reg[2] & addr_out[2];
  
  assign rresp_cam = rresp_cam_nxt & {2{match_i}};
  
  assign mask_last = fixed_mask_reg & match_i;

 //------------------------------------------------------------------------
 // Linked List, hazard and last control logic
 //------------------------------------------------------------------------

 //hazard Detection output
 //All transactions to the same id are stored as linked lists. A slice can only
 //report a hazard if it is at the bottom of the list. The new slice then points to the
 //one reporting the hazard.
 assign hazard = arid_match && last_reg && valid_reg && ~(can_complete && pop_slice);

 //Normal Register Enable
 assign default_reg_wr_en = (store && push_slice);

 //id Logic
 assign next_id_reg = hazard_id;

 always @(posedge aclk)
   begin : id_seq
      if (default_reg_wr_en)
         id_reg <= next_id_reg;
   end // id_seq

 //Pointer Logic ... this points to the previous transaction from the same id
 //Pointer is only valid when hazard is
 assign next_pointer_reg = hazard_pointer;

  always @(posedge aclk)
   begin : pointer_seq
      if (default_reg_wr_en)
         pointer_reg <= next_pointer_reg;
   end // pointer_seq

 //Last Logic
 //This indicates that this is the last item in a hazard queue
 assign next_last_reg = (store) ? 1'b1 : 
                        ((arid_match) ? 1'b0 : last_reg);

 assign last_reg_wr_en = (default_reg_wr_en || (arid_match && valid_reg && push_slice));
 
  always @(posedge aclk)
   begin : last_seq
      if (last_reg_wr_en)
         last_reg <= next_last_reg;
   end // last_seq

 //hazard Logic
 //pointer match
 assign pointer_match = (pointer_reg == match_pointer);

 //The only reason for updating this register is for a store or
 //it been promoted to the top of the queue .. => it will be 0
 assign next_hazard_reg = (store) ? hazard_in : 1'b0;

 assign hazard_reg_wr_en = (default_reg_wr_en || (pointer_match && valid_reg && pop_slice && rid_match));

  always @(posedge aclk)
   begin : hazard_seq
      if (hazard_reg_wr_en)
         hazard_reg <= next_hazard_reg;
   end // hazard_seq

 //valid_Logic

 assign next_valid_reg = (store && push_slice) || (|n_response_reg); 

 assign valid_reg_wr_en = default_reg_wr_en || (match_i && pop_slice);

   always @(posedge aclk or negedge aresetn)
   begin : valid_seq
      if (!aresetn) 
         valid_reg <= 1'b0;
      else if (valid_reg_wr_en)
         valid_reg <= next_valid_reg;
   end // valid_seq

  //Set valid ouput
  assign valid = valid_reg;

  //n response logic ... This is used to mask the first matches during a trans that 
  //has been downsized into multiple outgoing transactions;
  assign next_n_response_reg = (store && push_slice) ? n_response : (n_response_reg - 4'b0001);

  assign n_response_reg_wr_en =  (rid_match && ~hazard_reg && rlast_m && update) || default_reg_wr_en;

  always @(posedge aclk or negedge aresetn)
   begin : two_resp_seq
     if (!aresetn) 
         n_response_reg <= 4'b0;
     else if (n_response_reg_wr_en)
         n_response_reg <= next_n_response_reg;
   end // two_resp_seq

  //------------------------------------------------------------------------
  // addr Logic
  //------------------------------------------------------------------------

  //Detect if a boundary has been crossed 
  assign boundary_cross = |((addr_incr ^ {1'b0, addr_reg}) 
                          & ({1'b1, ~addr_mask_reg} | {1'b0,~downsize_reg}));
  
  //Determine the number of beats taking account of address
  always @(downsize_reg or addr_out or addr_mask_reg)
  begin : beats_masked_p
    
    beats_masked = {2{1'b0}};
    
    case (downsize_reg)
       3'd0    : beats_masked = (~addr_out[1:0]) & (addr_mask_reg[1:0]);
       3'd1    : beats_masked = ({{1{1'b0}}, ~addr_out[1]}) & (addr_mask_reg[1:0]);          
         
    endcase

  end  
  
  
  //Determine the number of beats taking account of address
  always @(downsize_reg or addr_mask_end_reg)
  begin : addr_end_masked_p
    
    addr_end_masked = {2{1'b0}};
    
    case (downsize_reg)
       3'd0    : addr_end_masked = (addr_mask_end_reg[1:0]);
       3'd1    : addr_end_masked = {{1{1'b0}}, addr_mask_end_reg[1]};          
        
    endcase
  end
  

  //determine value to increase address by
  always @(size_reg)
  begin : size_incr_p
    case (size_reg)
       2'd0    : size_incr = {3'b0, 1'b1}; // AXI_ASIZE_8
       2'd1    : size_incr = {2'b0, 2'b10};  // AXI_ASIZE_16         
       2'd2    : size_incr = {1'b0, 3'b100};  // AXI_ASIZE_32    
       2'd3    : size_incr = {3'b0, 1'b1};    //Unused case size_reg should never hit in normal operation
       default         : size_incr = {4'bx};
    endcase
  end

  //Masked address
  assign addr_incr = {1'b0, addr_reg} + size_incr;

  //addr_reg_incr 
  always @(addr_reg or addr_mask_reg or addr_incr)
  begin : addr_reg_nxt_p
     integer index_i;
     for (index_i = 0; index_i < 3 ; index_i = index_i + 1)
     begin
       if (addr_mask_reg[index_i] == 1'b1)
         addr_next[index_i] = addr_incr[index_i];
       else
         addr_next[index_i] = addr_reg[index_i];
     end
   end // addr_reg_nxt_p 

  //addr_req_wr
  assign addr_reg_wr = default_reg_wr_en || (match_i && update);

   // Masked according to narrow bus width
  assign next_addr_reg = (store && push_slice) ? addr : 
                          (addr_next & {{1{1'b1}},{2{1'b0}}});

  
  //Address incrementer register.
  always @(posedge aclk or negedge aresetn)
   begin : addr_seq
     if (!aresetn) 
         addr_reg <= 3'b0;
     else if (addr_reg_wr)
         addr_reg <= next_addr_reg;
   end // addr_reg

  //address and size Output - only if matched
  assign addr_out = addr_reg & {3{match_i}};
  // Create last mi transaction if n_response_n is zero or downsizing a fixed burst
  assign last_addr_match_i = (~|n_response_reg || (downsize_reg[2] & (~|addr_mask_reg)));
  assign last_addr_match   = last_addr_match_i;
  assign beat_complete     = boundary_cross;
  
  assign beat_number = bypass_reg ? {2{1'b0}} : 
                        ((last_addr_match_i && rlast_m) ? (addr_end_masked & {2{match_i}}) : 
                          ((beats_masked) & {2{match_i}}));


  
  //Identify downsize fixed transactions for which the addr tracker
  //must increment
  assign fixed_incr_addr = (~|addr_mask) & 
                            ((downsize[2] & (~addr[2])) 
                            );
                            

  //The size, addr_Mask and addr_mask_end registers are only updated when Slice is loaded
  assign next_addr_mask_reg = (fixed_incr_addr) ? {3{1'b1}} : addr_mask;
  
  
  always @(posedge aclk or negedge aresetn)
   begin : ardata_seq
     if (!aresetn) begin
         addr_mask_reg <= 3'b0;
         addr_mask_end_reg <= 2'b0;
         size_reg  <= 2'b0;
         bypass_reg <= 1'b0;
         downsize_reg <= 3'b0;
     end else if (default_reg_wr_en) begin
         addr_mask_reg <= next_addr_mask_reg;
         addr_mask_end_reg  <= addr_mask_end;
         size_reg <= size_in;
         bypass_reg <= bypass_in;
         downsize_reg <= downsize;
     end
   end // ardata_seq




`ifdef ARM_ASSERT_ON
//------------------------------------------------------------------------------
// OVL Assertions 
//------------------------------------------------------------------------------
// Include Standard OVL Defines
`include "std_ovl_defines.h"

  wire        size_out_range;
  
  assign      size_out_range = (size_reg > 2'd2);

//------------------------------------------------------------------------------
// OVL_ASSERT: Downsize_rd_cam_slice has received an unsupported AxSIZE
//------------------------------------------------------------------------------
// This OVL assertion should fire whenever the slice receives an unsupported
// AxSIZE.
//------------------------------------------------------------------------------
// OVL_ASSERT_RTL

  wire                    illegal_size_incr;        // Illegal size_incr

  // Signal an illegal total_bytes
  assign illegal_size_incr =  (size_incr == {3'b0, 1'b1}) & size_out_range;

  // OVL Assertion
  assert_never #(`OVL_FATAL,
                 `OVL_ASSERT,
                 "Input size_in to size_incr calculation has gone out of legal range")
  ovl_size_incr_illegal_asize
  (
    .clk        (aclk),
    .reset_n    (aresetn),
    .test_expr  (illegal_size_incr)
  );

//------------------------------------------------------------------------------
// OVL_ASSERT: Clock enables never unknown
//------------------------------------------------------------------------------
// This OVL assertion should fire whenever a clock gated term is X
//------------------------------------------------------------------------------
// OVL_ASSERT_RTL

  wire [6:0]                    rdata_buffer_enables;      

  // Signal an illegal total_bytes
  assign rdata_buffer_enables = {rdata_reg_en, 6'b0};
  

  // OVL Assertion
  assert_never_unknown #(`OVL_FATAL, 7,
                         `OVL_ASSERT,
                         "Clock enable has gone X")
  ovl_clock_gate_unknown
  (
    .clk        (aclk),
    .reset_n    (aresetn),
    .qualifier  (valid_reg),
    .test_expr  (rdata_buffer_enables & {7{nic400_ib_dma_axi4_cpu_ib_downsize_rd_chan_ysyx_rv32.rvalid_m}})
  );
// OVL_ASSERT_END
//------------------------------------------------------------------------------
`endif

endmodule

`include "nic400_ib_dma_axi4_cpu_ib_undefs_ysyx_rv32.v"
`include "Axi_undefs.v"

//------------------------------------------------------------------------------
//  End of File : $RCSfile: UpsizeAxi_rdata_cam_slice,v $
//------------------------------------------------------------------------------

